from flask import render_template, redirect, g, request, jsonify, current_app

from manager import app
from . import profile_blur
from ... import constants, db
from ...models import User, News, Category
from ...utils.common import login_require
from ...utils.formscheck import PassWordCheck
from ...utils.image_storage import image_storage
from ...utils.response_code import RET
from werkzeug.utils import secure_filename
from flask_restful import Api, Resource
from flask.views import MethodView




"""
请求路径: /user/user_follow
请求方式: GET
请求参数:p
返回值: 渲染user_follow.html页面,字典data数据
"""


@profile_blur.route('/user_follow')
@login_require
def user_follow():
    # 判断用户是否登录
    if not g.user:
        return redirect('/')
    page = request.args.get('p', 1)
    # 参数转换
    try:
        page = int(page)
    except Exception as e:
        current_app.logger.error(e)
        page = 1
    # 分页查询
    paginate = g.user.followed.paginate(page, 2, False)
    totalpage = paginate.pages
    currentpage = paginate.page
    idols = paginate.items
    idol_dict_list = [idol.to_dict() if idol else None for idol in idols]
    is_followed = False

    data = {
        'idol_dict_list': idol_dict_list,
        'totalpage': totalpage,
        'currentpage': currentpage
    }
    return render_template('news/user_follow.html', data=data)


# 创建api
api = Api(profile_blur)
"""
获取用户发布的新闻列表
请求路径: /user/news_list
请求方式:GET
请求参数:p
返回值:GET渲染user_news_list.html页面
"""


class UserNewsList(Resource):
    @login_require
    def get(self):
        # 1.获取参数
        page = request.args.get('p', 1)
        # 2.转换参数
        try:
            page = int(page)
        except Exception as e:
            current_app.logger.error(e)
            page = 1
        # 3.查询用户的所有发布新闻
        # 4.判断用户是否登录
        if not g.user:
            return redirect('/')
        # 5.查询用户发布的新闻
        # paginate = News.query.filter(News.user_id == g.user.id).order_by(News.create_time.desc()).paginate(page, 5, False)
        paginate = g.user.news_list.order_by(News.create_time.desc()).paginate(page, 5, False)
        totalpage = paginate.pages
        currentpage = paginate.page
        items = paginate.items
        news_dict_list = [news.to_review_dict() if news else None for news in items]

        # 6. 渲染页面
        data = {
            'news_dict_list': news_dict_list,
            'totalPage': totalpage,
            "currentPage": currentpage
        }

        return render_template('news/user_news_list.html', data=data)


profile_blur.add_url_rule('/news_list', view_func=UserNewsList.as_view('user_list'))
# 装逼的写法 restful(此处restful render_template时候不能渲染页面最终放弃了，还是用基于调度方法的类视图装逼一下)
# 注意，flask_restful反转蓝图时候，如果不指定endpoint 默认为 蓝图名.类名的小写
"""
请求路径: /user/news_release
请求方式:GET,POST
请求参数:GET无, POST ,title, category_id,digest,index_image,content
返回值:GET请求,user_news_release.html, data分类列表字段数据, POST,errno,errmsg
"""


class NewsRelease(MethodView):
    """
    1. 判断请求方式,如果是GET
    2. 携带分类数据渲染页面
    3. 如果是POST,获取参数
    4. 校验参数,为空校验
    5. 上传图片,判断是否上传成功
    6. 创建新闻对象,设置属性
    7. 保存到数据
    8. 返回响应


    """

    def get(self):
        # 查询所有种类
        category_list = Category.query.all()
        # 转换为字典
        category_dict_list = [category.to_dict() if category else None for category in category_list]
        data = {
            'category_dict_list': category_dict_list
        }
        # 渲染页面
        return render_template('news/user_news_release.html', data=data)

    @login_require
    def post(self):
        # 获取参数
        title = request.form.get('title')
        category_id = request.form.get('category_id')
        digest = request.form.get('digest')
        index_image = request.files.get('index_image')
        content = request.form.get('content')
        # 校验参数
        if not all([title, category_id, digest, content, index_image]):
            return jsonify(errno=RET.DATAERR, errmsg="参数不全")
        # 图片格式校验，必须是jpg,png
        filename = secure_filename(index_image.filename)
        if filename.split('.')[-1] not in ['png', 'jpg', 'jpeg']:
            return jsonify(errno=RET.DATAERR, errmsg="文件格式错误")
        # 上传图片
        try:
            # 读取图片为二进制上传
            image_name = image_storage(index_image.read())
        except Exception as e:
            current_app.logger.error(e)
            return jsonify(errno=RET.DBERR, errmsg="远程七牛云服务器错误")
        if not image_name:
            return jsonify(errno=RET.DATAERR, errmsg="上传图片失败")
        # 创建新闻对象
        news = News()
        news.title = title
        news.source = g.user.nick_name
        try:
            category_ids = int(category_id)
        except Exception as e:
            current_app.logger.error(e)
            return jsonify(errno=RET.DATAERR, errmsg="参数错误")
        news.category_id = category_ids
        news.digest = digest
        news.index_image_url = constants.QINIU_DOMIN_PREFIX + image_name
        news.content = content
        news.user_id = g.user.id
        news.status = 1  # 审核中
        try:
            db.session.add(news)
            db.session.commit()
        except Exception as e:
            current_app.logger.error(e)
            return jsonify(errno=RET.DBERR, errmsg="发布新闻失败，数据库异常")
        # 返回响应
        return jsonify(errno=RET.OK, errmsg="发布新闻成功")


# 注册
# api.add_resource(NewsRelease, '/news_release', endpoint='news_release')
profile_blur.add_url_rule('/news_release', view_func=NewsRelease.as_view('news_release'))
"""
请求路径: /user/collection
请求方式:GET
请求参数:p(第几页)
返回值: user_collection.html页面
"""


@profile_blur.route('/collection')
@login_require
def collection():
    # 获取参数
    page = request.args.get('p', 1)
    # 2. 参数类型转换
    try:
        page = int(page)
    except Exception as e:
        current_app.logger.error(e)
        page = 1
    # 3. 分页查询收藏的新闻
    try:
        paginate = g.user.collection_news.order_by(News.create_time.desc()).paginate(page, 5, False)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="分页获取搜藏新闻失败")
    # 4. 获取分页对象属性,总页数,当前页,当前页对象列表
    totalPage = paginate.pages
    currentpage = paginate.page
    items = paginate.items

    # 5. 将对象列表,转成字典列表
    news_list = [news.to_dict() if news else None for news in items]
    # 6. 拼接数据,渲染页面
    data = {
        'totalPage': totalPage,
        'currentpage': currentpage,
        "news_list": news_list
    }

    return render_template('news/user_collection.html', data=data)


"""
请求路径: /user/pass_info
请求方式:GET,POST
请求参数:GET无, POST有参数,old_password, new_password
返回值:GET请求: user_pass_info.html页面,data字典数据, POST请求: errno, errmsg
"""


@profile_blur.route('/pass_info', methods=['GET', 'POST'])
@login_require
def pass_info():
    """
    获取参数
    校验参数
    验证原密码
    确认两次密码是否一致
    展示密码修改页面
    :return:
    """
    # 1. get请求展示修改密码界面
    if request.method == 'GET':
        return render_template('news/user_pass_info.html')
    old_password = request.json.get('old_password')
    # 验证密码是否正确
    if not g.user.check_passowrd(old_password):
        return jsonify(errno=RET.DATAERR, errmsg="密码错误")
    new_password = request.json.get('new_password')
    new_password2 = request.json.get('new_password2')
    if not all([new_password, new_password2]):
        return jsonify(errno=RET.PARAMERR, errmsg="参数错误")
    if len(new_password) < 6 or len(new_password2) < 6:
        return jsonify(errno=RET.DATAERR, errmsg="密码长度必须大于六位数")
    if new_password != new_password2:
        return jsonify(errno=RET.DATAERR, errmsg="两次密码不一致")
    g.user.password = new_password

    # 返回响应
    return jsonify(errno=RET.OK, errmsg="修改密码成功")


"""
请求路径: /user/pic_info
请求方式:GET,POST
请求参数:无, POST有参数,avatar
返回值:GET请求: user_pci_info.html页面,data字典数据, POST请求: errno, errmsg,avatar_url
"""


@profile_blur.route('/pic_info', methods=['GET', 'POST'])
@login_require
def pic_info():
    """
    判断请求方式携带用户原有信息，渲染页面
    获取参数
    非空校验
    上传图片，判断图片是否上传成功
    将图片设置为用户对象
    返回响应
    :return:
    """
    # get 请求
    if request.method == 'GET':
        data = {
            'user_info': g.user.to_dict()
        }
        return render_template('news/user_pic_info.html', data=data)
    # post请求，上传图片
    # 1.获取参数
    avatar = request.files.get('avatar')
    # 参数校验
    if not avatar:
        return jsonify(errno=RET.NODATA, errmsg="参数错误")
    # 文件格式校验，必须是jpg,png,jpeg
    filename = secure_filename(avatar.filename)
    if filename.split('.')[-1] not in ['png', 'jpg', 'jpeg']:
        return jsonify(errno=RET.DATAERR, errmsg="文件格式错误")
    try:
        image_name = image_storage(avatar.read())
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.THIRDERR, errmsg="第三方网络异常")
    if not image_name:
        return jsonify(errno=RET.NODATA, errmsg="上传失败")
    # 保存图片名到数据库
    g.user.avatar_url = image_name
    # 返回响应
    data = {
        'avatar_url': constants.QINIU_DOMIN_PREFIX + image_name
    }
    return jsonify(errno=RET.OK, errmsg="上传图片成功", data=data)


"""
请求路径: /user/base_info
请求方式:GET,POST
请求参数:POST请求有参数,nick_name,signature,gender
返回值:errno,errmsg
"""


@profile_blur.route('/base_info', methods=['GET', 'POST'])
@login_require
def base_info():
    """
    get请求：携带用户信息，渲染页面
    post请求
    1.获取参数
    2.非空校验
    3.修改数据
    4.提交页面
    5.返回响应
    :return:
    """
    # 1. 判断请求
    if request.method == 'GET':
        if not g.user:
            return redirect('/')
        data = {
            'user_info': g.user.to_dict()
        }
        return render_template('news/user_base_info.html', data=data)

    # 若为post请求 后台获取参数
    signature = request.json.get('signature', None)
    gender = request.json.get('gender', None)
    nick_name = request.json.get('nick_name', None)
    # 参数校验
    if not all([gender, nick_name]):
        return jsonify(errno=RET.PARAMERR, errmsg="参数错误")
    # 唯一性校验
    # 1.查询数据库是否已经有该昵称 因为昵称唯一
    user = User.query.filter(User.nick_name == nick_name).first()
    if user:
        return jsonify(errno=RET.DATAERR, errmsg="该昵称已存在")
    # 性别校验
    if gender not in ['MAN', 'WOMAN']:
        return jsonify(errno=RET.DATAERR, errmsg="性别异常")
    g.user.signature = signature
    g.user.nick_name = nick_name
    g.user.gender = gender
    # 返回响应
    return jsonify(errno=RET.OK, errmsg="修改成功")


@profile_blur.route('/user')
@login_require
def user_index():
    if not g.user:
        return redirect('/')
    data = {
        'user_info': g.user.to_dict()
    }
    return render_template('news/user.html', data=data)
